package org.framework.common.api.support.model;

import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.framework.common.api.support.annotation.Tree;
import org.framework.common.api.support.annotation.TreeType;
import org.framework.common.ext.util.StringUtil;
import org.springframework.util.ReflectionUtils;

/**
 * 树结构数据模型
 * <p>描述: </p>
 * <p>Company: Professional</p>
 * @author chanlong(陈龙)
 * @date 2016年3月30日 上午10:48:04
 * @version 1.0.2016
 */
public class TreeModel implements Serializable {

	/** serialVersionUID(long):. */
	private static final long serialVersionUID = -6653721343614788814L;

	private String id;
	
	private String key;
	
	private String pid;
	
	private String text;
	
	private String type;
	
	private String code;
	
	private Map<String, Object> state;
	
	private List<TreeModel> nodes;
	
	/**
	 * 创建树结构数据.
	 * @param result
	 * @param checked
	 * @return
	 * @author chanlong(陈龙)
	 * @date 2016年4月1日 下午3:46:14
	 */
	public static TreeModel[] create(final List<?> result, final String... checked){
		List<TreeModel> trees = new ArrayList<TreeModel>();
		
		for (Object bean : result) {
			TreeModel tree = new TreeModel();
			
			ReflectionUtils.doWithMethods(bean.getClass(), tree.new MethodCallback(tree, bean));
			
			// 选中已选资源
			for(String check : checked){
				if(tree.getId().equals(check)){
					tree.addState("checked", true);
				}
			}
			
			// 构造同步树
			sync(tree.getKey(), tree, trees);
		}
		
		return trees.toArray(new TreeModel[trees.size()]);
	}
	
	/**
	 * 递归创建同步树（一次加载所有树节点）.
	 * 注：查询结果必须符合树结构排序
	 * @param key 父节点id
	 * @param tree 树模型对象
	 * @param trees 树模型集合
	 * @author chanlong(陈龙)
	 * @date 2015年8月28日  下午12:19:22
	 */
	public static void sync(final String key, TreeModel tree, List<TreeModel> result) {
		// 创建子节点
		if (result != null && (StringUtil.isEmpty(tree.getPid()) || key.equals(tree.getPid()))) {
			result.add(tree);
		} else if(result != null){
			for (int i = 0, size = result.size(); i < size; i++) {
				TreeModel parent = result.get(i);
				
				String pid = parent.getId();
				if(pid.equals(tree.getPid())){
					sync(pid, tree, parent.getNodes(new ArrayList<TreeModel>()));
				}else{
					sync(pid, tree, parent.getNodes());
				}
			}
		}
	}
	
	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getKey() {
		return key;
	}

	public void setKey(String key) {
		this.key = key;
	}

	public String getPid() {
		return pid;
	}

	public void setPid(String pid) {
		this.pid = pid;
	}

	public String getText() {
		return text;
	}

	public void setText(String text) {
		this.text = text;
	}

	public String getType() {
		return type;
	}

	public void setType(String type) {
		this.type = type;
	}

	public String getCode() {
		return code;
	}

	public void setCode(String code) {
		this.code = code;
	}

	public Map<String, Object> getState() {
		return state;
	}
	
	public Map<String, Object> getState(Map<String, Object> state) {
		if(this.state == null){
			this.state = state;
		}
		return this.state;
	}

	public void setState(Map<String, Object> state) {
		this.state = state;
	}

	public void addState(final String key, final Object value) {
		if(this.state == null){
			this.state = new HashMap<String, Object>();
		}
		this.state.put(key, value);
	}
	
	public List<TreeModel> getNodes() {
		return nodes;
	}
	
	public List<TreeModel> getNodes(List<TreeModel> nodes) {
		if(this.nodes == null){
			this.nodes = nodes;
		}
		return this.nodes;
	}

	public void setNodes(List<TreeModel> nodes) {
		this.nodes = nodes;
	}
	
	public void addNode(TreeModel tree){
		if(this.nodes == null){
			this.nodes = new ArrayList<TreeModel>();
		}
		this.nodes.add(tree);
	}
	
	/*
	 * 方法回调函数
	 */
	private class MethodCallback implements org.springframework.util.ReflectionUtils.MethodCallback{
		
		private Object bean;
		private TreeModel model;
		
		private MethodCallback(TreeModel model, Object bean) {
			this.bean = bean;
			this.model = model;
		}
		
		@Override
		public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
			Tree tree = method.getAnnotation(Tree.class);
			try {
				if(tree != null){
					TreeType[] types = tree.type();
					for (TreeType type : types) {
						switch (type) {
							case ID:
								Object id = ReflectionUtils.invokeMethod(method, bean);
								model.setId(String.valueOf(id));
							break;
							case PID:
								Object pid = ReflectionUtils.invokeMethod(method, bean);
								model.setPid(String.valueOf(pid));
							break;
							case KEY:
								Object key = ReflectionUtils.invokeMethod(method, bean);
								model.setKey(String.valueOf(key));
							break;
							case TEXT:
								Object text = ReflectionUtils.invokeMethod(method, bean);
								model.setText(String.valueOf(text));
							break;
							case CODE:
								Object code = ReflectionUtils.invokeMethod(method, bean);
								model.setCode(String.valueOf(code));
							break;
							case TYPE:
								Object value = ReflectionUtils.invokeMethod(method, bean);
								model.setType(String.valueOf(value));
							break;
							default:
								model.setId(String.valueOf(method.invoke(bean)));
								model.setText(String.valueOf(method.invoke(bean)));
							break;
						}
					}
				}
			} catch (InvocationTargetException e) {
				e.printStackTrace();
			}
		}
	}
}
